// 将原先一个的读写锁的map，拆分成多个map，成为zone_map
// 实现更低粒度的高并发map，契合读写相近的情况
// 支持自定义分片规则：包括 hash算法 & 分片数目
package cmap

import (
	"sort"
	"sync"
)

// Hash 函数
type Hash func(string) uint32

type ZoneMap struct {
	zones  []*zone
	hashTo Hash // 散列算法
}

// 基本分区
type zone struct {
	mp           map[string]interface{}
	sync.RWMutex // 读写锁
}

// 基本的创建方式：32个分区
func New() ZoneMap {
	return NewWith(baseHash32, 32)
}

// 自定义散列函数 & 大小的创建方式
func NewWith(to Hash, size int) ZoneMap {
	if to == nil {
		to = baseHash32
	}
	return ZoneMap{
		zones:  initZoneMap(size),
		hashTo: to,
	}
}

// 防止不合规大小尽量保持在8~64
func initZoneMap(size int) []*zone {
	// 设置在 8 ~ 64 且是2的幂
	arr := []int{8, 16, 32, 64}
	if size >= arr[len(arr)-1] {
		size = arr[len(arr)-1]
	} else {
		size = arr[sort.SearchInts(arr, size)]
	}
	// 初始化 []*zone
	ret := make([]*zone, size)
	for i := 0; i < size; i++ {
		ret[i] = &zone{mp: make(map[string]interface{})}
	}
	return ret
}

// 基本散列算法，参考fnv32
func baseHash32(key string) uint32 {
	hash := uint32(2166136261)
	const p = uint32(16777619)
	for i := 0; i < len(key); i++ {
		hash = (uint32(key[i]) ^ hash) * p
	}
	hash += hash << 13
	hash ^= hash >> 7
	hash += hash << 3
	hash ^= hash >> 17
	hash += hash << 5
	return hash
}

// 获取ZoneMap分区数目
func (m ZoneMap) Size() int {
	return len(m.zones)
}

// 获取基本的zone分区
func (m ZoneMap) GetZone(key string) *zone {
	return m.zones[m.hashTo(key)%uint32(m.Size())]
}

// 获取基本的zone分区,添加了索引
func (m ZoneMap) GetZoneWithIndex(key string) (*zone, uint32) {
	index := m.hashTo(key) % uint32(m.Size())
	return m.zones[index], index
}

// Set & Get & Delete
func (m *ZoneMap) Set(key string, value interface{}) {
	zone := m.GetZone(key)
	zone.Lock()
	defer zone.Unlock()
	zone.mp[key] = value
}

func (m *ZoneMap) Get(key string) (interface{}, bool) {
	zone := m.GetZone(key)
	zone.RLock()
	defer zone.RUnlock()
	v, ok := zone.mp[key]
	return v, ok
}

func (m *ZoneMap) Delete(key string) {
	zone := m.GetZone(key)
	zone.Lock()
	defer zone.Unlock()
	delete(zone.mp, key)
}

// GetOrSet，如果有就获取，不然就删除，如果是首次初始化就返回true
func (m *ZoneMap) GetOrSet(key string, value interface{}) bool {
	zone := m.GetZone(key)
	zone.Lock()
	defer zone.Unlock()
	_, ok := zone.mp[key]
	if !ok {
		zone.mp[key] = value
	}
	return !ok
}

// 大规模set，集中处理多次set取锁的问题
func (m *ZoneMap) MoreSet(t map[string]interface{}) {
	for k, v := range t {
		zone := m.GetZone(k)
		zone.Lock()
		zone.mp[k] = v
		zone.Unlock()
	}
}

// Delete自定义删除后的回调判断
type DeleteCallBack func(key, value interface{}, exist bool) interface{}

func (m *ZoneMap) DeleteFunc(key string, back DeleteCallBack) interface{} {
	zone := m.GetZone(key)
	zone.Lock()
	defer zone.Unlock()
	v, ok := zone.mp[key]
	if ok {
		delete(zone.mp, key)
	}
	return back(key, v, ok)
}

// 遍历条件，回调为false的时候停止遍历，参考sync.map的range
func (m *ZoneMap) Range(f func(key string, value interface{}) bool) {
	for _, zone := range m.zones {
		zone.Lock()
		for k, v := range zone.mp {
			if !f(k, v) {
				zone.Unlock()
				return
			}
		}
		zone.Unlock()
	}
}
